package v1

import (
	"context"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/jinzhu/copier"
	"go.uber.org/zap"
	"golang.org/x/sync/errgroup"
	"math/rand"
	"maya-service/bll"
	log "maya-service/collector/logger"
	"maya-service/config"
	"maya-service/model"
	"maya-service/model/po"
	mallPo "maya-service/model/po/mall"
	"maya-service/server/web/middleware"
	"maya-service/utils"
	"maya-service/utils/request"
	"net/http"
	"regexp"
	"strings"
	"time"
	"unicode"
)

var Mall = &mall{}

func init() {
	RegisterRouter(Mall)
}

type mall struct{}

// Init
func (a *mall) Init(r *gin.RouterGroup) {
	g := r.Group("/mall", middleware.ApiKeyCheck())
	{
		// 主题列表
		g.POST("/topicList", a.topicList)
		// 设置推荐
		g.POST("/updateRecommend", a.updateRecommend)
		// 主题相关
		g.POST("/topic/list", AiModule.list)
	}

	g1 := r.Group("/mall")
	{
		// 题目列表
		g1.POST("/questionList", a.questionList)
		g1.POST("/productInfo", a.productInfo)
	}

	g2 := r.Group("/mall" /*middleware.ShopAuth()*/)
	{
		// 题目列表
		g2.POST("/createOrUpdateQuestion", a.createOrUpdateQuestion)
	}
}

// createOrUpdateQuestion 创建或者更新题目
func (a *mall) productInfo(c *gin.Context) {
	var (
		in  = &po.ProductInfoReq{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	token := c.GetHeader("Authorization")
	if token == "" {
		c.JSON(http.StatusUnauthorized, nil)
		c.Abort()
		return
	}

	// 物品信息
	goodsInfo, err := request.GetProductInfo(token, config.Conf.Env, in.ProductId)
	if err != nil {
		utils.ResponseOkWithError(c, err.Error())
		return
	}

	resp := po.ProductInfoResp{ProductId: in.ProductId}
	if goodsInfo.DefaultProduct.ProductId != 0 {
		resp.GoodsPrice = goodsInfo.DefaultProduct.ProductPrice
		resp.GoodsName = goodsInfo.DefaultProduct.GoodsName
	}

	utils.ResponseOk(c, resp)
}

func (a *mall) RefreshGuideAnswer() {
	list, err := bll.AiQuestion.List(context.Background(), &model.AiQuestionListRequest{Index: 1, Size: 10000})
	if err != nil {
		return
	}
	for _, v := range list.List {
		if v.ReferenceAnswer == "" {
			continue
		}

		data := []byte(v.ReferenceAnswer)
		value := string(data[0:1])
		if value == "#" || strings.Contains(v.GuideAnswer, "**") {
			continue
		}

		// 生成markdown
		var content, conversationId string
		userId := fmt.Sprintf("%v", rand.Intn(10000))
		conversationId = bll.CreateConversation(userId, "7459732707900850239", "pat_5Do9945xBDp7pBeX7X8DheznuEpm8ijL41aKRp60sbWnJeP2MbmHce2GUZJnyYmu", "")
		content, _, err = bll.SendMessage("7459732707900850239", "pat_5Do9945xBDp7pBeX7X8DheznuEpm8ijL41aKRp60sbWnJeP2MbmHce2GUZJnyYmu", conversationId, userId, v.ReferenceAnswer, nil)
		if content == "" || content == "暂时无法理解你的诉求，请重新组织下语言" {
			continue
		} else {
			_ = bll.AiQuestion.Update(context.Background(), &model.AiQuestionUpdateRequest{
				Id:          v.Id,
				GuideAnswer: &content,
			})
		}

		// ai 优化
		/*conversationId = CreateConversation(userId, "7458183535627780105", "pat_5Do9945xBDp7pBeX7X8DheznuEpm8ijL41aKRp60sbWnJeP2MbmHce2GUZJnyYmu", "")
		content, _, err = SendMessage("7458183535627780105", "pat_5Do9945xBDp7pBeX7X8DheznuEpm8ijL41aKRp60sbWnJeP2MbmHce2GUZJnyYmu", conversationId, userId, content, nil)
		if content != "" {
			_ = AiQuestion.Update(context.Background(), &model.AiQuestionUpdateRequest{
				Id:          v.Id,
				GuideAnswer: &content,
			})
		} else {
			log.Error("#### 生成markdown 文本报错 ", zap.Any("err", err))
		}*/
	}
}

// createOrUpdateQuestion 创建或者更新题目
func (a *mall) createOrUpdateQuestion(c *gin.Context) {
	var (
		in  = &model.AiQuestionUpdateRequest{}
		err error
	)

	defer func() {
		go func() {
			defer utils.ExceptionCatch()
			a.RefreshGuideAnswer()
		}()
	}()

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	fmt.Println("############# createOrUpdateQuestion 1", zap.Any("time", time.Now().String()))

	// 查询合集
	if in.GoodsId == nil {
		utils.ResponseOkWithError(c, "合集ID不能为空")
		return
	}

	// 创建
	if in.Id == 0 {
		findResult, _ := bll.GoodsCollector.Find(c.Request.Context(), &model.GoodsCollectorInfoRequest{
			Id: *in.GoodsId,
		})
		if findResult == nil || findResult.Id <= 0 {
			utils.ResponseOkWithError(c, "合集不存在")
			return
		}

		createReq := &model.AiQuestionCreateRequest{}
		_ = copier.Copy(createReq, in)
		questionId, err := bll.AiQuestion.Create(c.Request.Context(), createReq)
		if err != nil {
			utils.ResponseOkWithError(c, err.Error())
			return
		}
		fmt.Println("############# createOrUpdateQuestion 2", zap.Any("time", time.Now().String()), zap.Any("findResult", utils.ToJsonString(findResult)))
		if in.IsBindProduct != nil && *in.IsBindProduct == 1 {
			dto := mallPo.ProductOpenDTO{
				ThirdProductId: fmt.Sprintf("%v", questionId),
			}
			if in.Stock != nil {
				dto.ProductStock = *in.Stock
			}
			if in.Price != nil {
				dto.ProductPrice = fmt.Sprintf("%v", *in.Price)
			}
			if in.UpDown != nil {
				dto.State = *in.UpDown
			}
			if in.Topic != nil {
				dto.ProductName = *in.Topic
			}
			// 创建商品
			productInfo, err := request.CreateOrUpdateProduct(c.GetHeader("Authorization"), config.Conf.Env, mallPo.CreateProductRequest{
				GoodsId: findResult.ThirdGoodsId,
				ProductList: []mallPo.ProductOpenDTO{
					dto,
				},
			})
			fmt.Println("############# createOrUpdateQuestion 3", zap.Any("time", time.Now().String()))
			if err != nil {
				go func(questionId int64) {
					defer utils.ExceptionCatch()
					_ = bll.AiQuestion.Delete(context.Background(), &model.AiQuestionDeleteRequest{
						Id: questionId,
					})
				}(questionId)
				utils.ResponseOkWithError(c, err.Error())
				return
			}

			log.Info("mall.createOrUpdateQuestion 1", zap.Any("productInfo", productInfo))
			go func(productInfo mallPo.CreateProductResponse) {
				defer utils.ExceptionCatch()
				for i := 0; i < len(productInfo.ProductList); i++ {
					if fmt.Sprintf("%v", questionId) == productInfo.ProductList[i].ThirdProductId {
						_ = bll.AiQuestion.Update(context.Background(), &model.AiQuestionUpdateRequest{
							Id:          questionId,
							ProductId:   &productInfo.ProductList[i].ProductId,
							CollectorId: &findResult.Id,
						})
					}
				}
			}(productInfo)
		}

		utils.ResponseOk(c, struct {
			QuestionId int64 `json:"questionId"`
		}{QuestionId: questionId})
		return
	}

	var errGroup errgroup.Group
	var findResult *model.GoodsCollectorInfo
	errGroup.Go(func() error {
		//
		findResult, _ = bll.GoodsCollector.Find(c.Request.Context(), &model.GoodsCollectorInfoRequest{
			Id: *in.GoodsId,
		})
		if findResult == nil || findResult.Id <= 0 {
			return fmt.Errorf("合集不存在")
		}

		return nil
	})

	var questionInfo *model.AiQuestionInfo
	errGroup.Go(func() error {
		questionInfo, _ = bll.AiQuestion.Find(c.Request.Context(), &model.AiQuestionInfoRequest{
			Id: in.Id,
		})

		if questionInfo == nil || questionInfo.Id <= 0 {
			return fmt.Errorf("题目不存在")
		}

		return nil
	})

	if err = errGroup.Wait(); err != nil {
		utils.ResponseOkWithError(c, err.Error())
		return
	}

	err = bll.AiQuestion.Update(c.Request.Context(), in)
	if err != nil {
		utils.ResponseOkWithError(c, err.Error())
		return
	}

	// 更新商品库存
	if in.Stock != nil || in.Price != nil || in.UpDown != nil {
		dto := mallPo.ProductOpenDTO{
			ThirdProductId: fmt.Sprintf("%v", in.Id),
		}
		if in.ProductId != nil {
			dto.ProductId = *in.ProductId
		}
		if in.Stock != nil {
			dto.ProductStock = *in.Stock
		}

		if in.Price != nil {
			dto.ProductPrice = fmt.Sprintf("%v", *in.Price)
		}

		if in.Topic != nil {
			dto.ProductName = *in.Topic
		} else {
			dto.ProductName = questionInfo.Topic
		}

		if in.UpDown != nil {
			dto.State = *in.UpDown
		}

		// 更新商品
		productInfo, err := request.CreateOrUpdateProduct(c.GetHeader("Authorization"), config.Conf.Env, mallPo.CreateProductRequest{
			GoodsId: findResult.ThirdGoodsId,
			ProductList: []mallPo.ProductOpenDTO{
				dto,
			},
		})

		if err == nil {
			go func(questionId, collectorId int64, productInfo mallPo.CreateProductResponse) {
				for i := 0; i < len(productInfo.ProductList); i++ {
					if fmt.Sprintf("%v", in.Id) == productInfo.ProductList[i].ThirdProductId {
						_ = bll.AiQuestion.Update(context.Background(), &model.AiQuestionUpdateRequest{
							Id:          questionId,
							ProductId:   &productInfo.ProductList[i].ProductId,
							CollectorId: &collectorId,
						})
					}
				}
			}(in.Id, findResult.Id, productInfo)

			utils.ResponseOk(c, nil)
		} else {
			log.Info("mall.createOrUpdateQuestion 2", zap.Any("dto", dto))
			utils.ResponseOkWithError(c, err.Error())
		}
		return
	}

	utils.ResponseOk(c, struct {
		QuestionId int64 `json:"questionId"`
	}{QuestionId: in.Id})
	return
}

// TopicList 主题列表
func (a *mall) topicList(c *gin.Context) {
	var (
		in  = &model.AiModuleListRequest{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	// 根据热度排序
	in.OrderByHeat = true
	ret, err := bll.AiModule.List(c.Request.Context(), in)
	if err != nil {
		utils.ResponseOkWithError(c, err.Error())
		return
	}

	utils.ResponseOk(c, ret)
	return
}

func ExtractInfo(s string) (han string, num int) {
	// 提取前两个汉字
	for _, r := range s {
		if unicode.Is(unicode.Han, r) && len(han) < 2*3 { // 中文按3字节计算
			han += string(r)
		}
		if len(han) >= 2*3 { // 提前退出循环
			break
		}
	}

	// 提取期数数字
	if match := regexp.MustCompile(`第(\d+)期`).FindStringSubmatch(s); len(match) > 1 {
		fmt.Sscanf(match[1], "%d", &num)
	} else if match = regexp.MustCompile(`(\d+)期`).FindStringSubmatch(s); len(match) > 1 {
		fmt.Sscanf(match[1], "%d", &num)
	} else {
		num = -1
	}

	return
}

// _aiQuestionSearch 搜索
func (a *mall) _aiQuestionSearch(topic string) (moduleId int, issue int, err error) {
	han, num := ExtractInfo(topic)
	if len(han) <= 0 && num == -1 {
		err = fmt.Errorf("没有符合条件的")
		return
	}

	issue = num

	find, _ := bll.AiModule.Find(context.Background(), &model.AiModuleInfoRequest{
		Name: han,
	})
	if find != nil && find.Id > 0 {
		moduleId = int(find.Id)
	}

	return
}

// QuestionList 题目列表
func (a *mall) questionList(c *gin.Context) {
	var (
		in  = &model.AiQuestionListRequest{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	if in.Topic != nil {
		moduleId, issue, err := a._aiQuestionSearch(*in.Topic)
		if err == nil {
			if moduleId > 0 {
				in.Module = &moduleId
			}

			if issue > 0 {
				in.Issue = &issue
			}

			in.Topic = nil
		}
	}

	// 根据热度排序
	in.IsRecommendList = true
	ret, err := bll.AiQuestion.List(c.Request.Context(), in)
	if err != nil {
		utils.ResponseOkWithError(c, err.Error())
		return
	}

	utils.ResponseOk(c, ret)
	return
}

// updateRecommend 设置推荐
func (a *mall) updateRecommend(c *gin.Context) {
	var (
		in  = &model.AiQuestionUpdateRequest{}
		err error
	)

	if err = c.ShouldBindJSON(in); err != nil {
		c.Error(err)
		return
	}

	err = bll.AiQuestion.Update(c.Request.Context(), in)
	if err != nil {
		utils.ResponseOkWithError(c, err.Error())
		return
	}

	utils.ResponseOk(c, nil)
	return
}
